#include "timer.h"

#include "util.h"

#include "log.h"

static sylar::Logger::LoggerPtr g_logger = SYLAR_LOG_NAME("system");

namespace sylar
{

static void OnTimer(std::weak_ptr<void> weak_cond, std::function<void(void)> cb)
{
    std::shared_ptr<void> tmp  = weak_cond.lock();
    if (tmp)
    {
        cb();
    }
}

Timer::Timer(uint64_t ms, std::function<void(void)> cb, bool recurring, TimerManger *manger)
    :m_recurring(recurring)
    , m_ms(ms)
    , m_manger(manger)
    , m_cb(cb)
{
    m_next = sylar::GetCurrentMs() + m_ms;
}

Timer::Timer(uint64_t next)
    : m_next(next)
{

}

bool Timer::cancel()
{
    TimerManger::RWMutexType::WriteLock lock(m_manger->m_mutx);
    if (m_cb)
    {
        m_cb = nullptr;
        auto it = m_manger->m_timers.find(shared_from_this());
        m_manger->m_timers.erase(it);
        return true;
    }
    return false;
}

bool Timer::refresh()
{
    TimerManger::RWMutexType::WriteLock lock(m_manger->m_mutx);
    if (!m_cb)
    {
        return false;
    }
    m_cb = nullptr;
    auto it = m_manger->m_timers.find(shared_from_this());
    if(it == m_manger->m_timers.end())
    {
        return false;
    }
    m_manger->m_timers.erase(it);

    m_next = sylar::GetCurrentMs() + m_ms;
    m_manger->m_timers.insert(shared_from_this());
    return true;
}

// bool Timer::reset(uint64_t ms, bool from_now) {
//     if(ms == m_ms && !from_now) {
//         return true;
//     }
//     TimerManger::RWMutexType::WriteLock lock(m_manger->m_mutx);
//     if(!m_cb) {
//         return false;
//     }
//     auto it = m_manger->m_timers.find(shared_from_this());
//     if(it == m_manger->m_timers.end()) {
//         return false;
//     }
//     m_manger->m_timers.erase(it);
//     uint64_t start = 0;
//     if(from_now) {
//         start = sylar::GetCurrentMs();
//     } else {
//         start = m_next - m_ms;
//     }
//     m_ms = ms;
//     m_next = start + m_ms;
//     m_manger->addTimer(shared_from_this(), lock);
//     return true;

// }

bool Timer::reset(uint64_t ms, bool from_now)
{   // from_now 强制改
    if (ms == m_ms && !from_now)
    {
        return true;
    }

    TimerManger::RWMutexType::WriteLock lock(m_manger->m_mutx);
    if (!m_cb)
    {
        return false;
    }
    //m_cb = nullptr;
    auto it = m_manger->m_timers.find(shared_from_this());
    if(it == m_manger->m_timers.end())
    {
        return false;
    }
    m_manger->m_timers.erase(it);

    uint64_t start = 0;
    if (from_now)
    {
        start = sylar::GetCurrentMs();
    }
    else
    {
        start = m_next - m_ms;
    }

    m_ms = ms;
    m_next = start + ms;
    m_manger->addTimer(shared_from_this(), lock);
    return true;
}

bool Timer::Comparator::operator()(const Timer::ptr &lhs, const Timer::ptr &rhs) const
{
    if (!lhs && !rhs)
    {
        return false;
    }

    if (!lhs)
    {
        return true;
    }

    if (!rhs)
    {
        return false;
    }

    if (lhs->m_next < rhs->m_next)
    {
        return true;
    }
    if (lhs->m_next > rhs->m_next)
    {
        return false;
    }

    return lhs.get() < rhs.get();
}

TimerManger::TimerManger()
{
    m_previoseTime = sylar::GetCurrentMs();
}

TimerManger::~TimerManger()
{
}

Timer::ptr TimerManger::addTimer(uint64_t ms, std::function<void(void)> cb, bool recurring)
{
    Timer::ptr timer = std::make_shared<Timer>(ms, std::move(cb), recurring, this);
    //Timer::ptr timer(new Timer(ms, std::move(cb), recurring, this));
    RWMutexType::WriteLock lock(m_mutx);

    addTimer(timer, lock);
    // auto it = m_timers.insert(timer).first;
    // bool at_front = (it == m_timers.begin());
    // lock.unlock();
    // if (at_front)
    // {
    //     onTimerInserFront();
    // }
    return timer;
}

Timer::ptr TimerManger::addConditionTimer(uint64_t ms, std::function<void(void)> cb, std::weak_ptr<void> weak_cond, bool recurring)
{
    return addTimer(ms, std::bind(&OnTimer, weak_cond, cb), recurring);
}

uint64_t TimerManger::getNextTimer()
{
    RWMutexType::ReadLock lock(m_mutx);
    m_tickled = false;
    if (m_timers.empty())
    {
        return ~0ull;
    }
    const Timer::ptr& next = *m_timers.begin();

    uint64_t now_ms = sylar::GetCurrentMs();
    if(now_ms >= next->m_next) 
    {
        return 0;
    } 
    else 
    {
        return next->m_next - now_ms;
    }
}

void TimerManger::listExpiredCb(std::vector<std::function<void()> >& cbs) {
    uint64_t now_ms = sylar::GetCurrentMs();
    std::vector<Timer::ptr> expired;
    {
        RWMutexType::ReadLock lock(m_mutx);
        if(m_timers.empty()) {
            return;
        }
    }
    RWMutexType::WriteLock lock(m_mutx);
    if(m_timers.empty()) {
        return;
    }
    bool rollover = detectClockRollover(now_ms);
    if(!rollover && ((*m_timers.begin())->m_next > now_ms)) {
        return;
    }

    Timer::ptr now_timer(new Timer(now_ms));
    auto it = rollover ? m_timers.end() : m_timers.lower_bound(now_timer);
    while(it != m_timers.end() && (*it)->m_next == now_ms) {
        ++it;
    }
    expired.insert(expired.begin(), m_timers.begin(), it);
    m_timers.erase(m_timers.begin(), it);
    cbs.reserve(expired.size());

    for(auto& timer : expired) {
        cbs.push_back(timer->m_cb);
        if(timer->m_recurring) {
            timer->m_next = now_ms + timer->m_ms;
            m_timers.insert(timer);
        } else {
            timer->m_cb = nullptr;
        }
    }
}

// void TimerManger::listExpiredCb(std::vector<std::function<void(void)>> &cbs)
// {
//     uint64_t ullNowMs = sylar::GetCurrentMs();
//     std::vector<Timer::ptr> expired;

//     {
//         RWMutexType::ReadLock lock(m_mutx);
//         if (m_timers.empty())
//         {
//             return;
//         }
//     }

//     RWMutexType::WriteLock lock(m_mutx);

//     if (m_timers.empty())
//     {
//         return;
//     }

//     bool rollover = detectClockRollover(ullNowMs);
//     if (!rollover && (*m_timers.begin())->m_next > ullNowMs)
//     {
//         return;
//     }

//     if (m_timers.empty())
//     {
//         return ;
//     }

//     Timer::ptr now_timer(new Timer(ullNowMs));
//     auto it = rollover ? m_timers.end() : m_timers.lower_bound(now_timer);
//     while (it != m_timers.end() && (*it)->m_next == ullNowMs)
//     {
//         ++it;
//     }

//     expired.insert(expired.begin(), m_timers.begin(), it);
//     m_timers.erase(m_timers.begin(), it);

//     cbs.reserve(expired.size());

//     for(auto& timer : expired) 
//     {
//         cbs.push_back(timer->m_cb);
//         if(timer->m_recurring) 
//         {
//             timer->m_next = ullNowMs + timer->m_ms;
//             m_timers.insert(timer);
//         } 
//         else
//         {
//             timer->m_cb = nullptr;
//         }
//     }
// }

bool TimerManger::hasTimer()
{
    RWMutexType::ReadLock lock(m_mutx);
    return !m_timers.empty();
}

void TimerManger::addTimer(Timer::ptr val, RWMutexType::WriteLock& lock)
{
    // auto it = m_timers.insert(val).first;
    // SYLAR_LOG_DEBUG(g_logger) << "m_timers.size() " << m_timers.size();
    // bool at_front = (it == m_timers.begin()) && !m_tickled;
    // if (at_front)
    // {
    //     m_tickled = true;
    // }

    // lock.unlock();
    // if (at_front)
    // {
    //     onTimerInserFront();
    // }

    auto it = m_timers.insert(val).first;
    bool at_front = (it == m_timers.begin()) && !m_tickled;
    if(at_front) {
        m_tickled = true;
    }
    lock.unlock();

    if(at_front) {
        onTimerInserFront();
    }
}

bool TimerManger::detectClockRollover(uint64_t now_ms)
{
    // bool rollover = false;
    // if (now_ms < m_previoseTime && now_ms < m_previoseTime - 60 * 60 * 1000)
    // {
    //     rollover  = true;
    // }
    // m_previoseTime = now_ms;
    // return rollover;

    bool rollover = false;
    if(now_ms < m_previoseTime &&
            now_ms < (m_previoseTime - 60 * 60 * 1000)) {
        rollover = true;
    }
    m_previoseTime = now_ms;
    return rollover;
}
}
